package com.ronan.imweb.config;

import cn.hutool.extra.servlet.ServletUtil;
import com.ronan.common.exception.ApiException;
import com.ronan.common.response.ResultCode;
import com.ronan.imweb.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * FileName    : com.withufuture.config
 * Description : 防刷拦截器
 *
 * @author : ronan
 * @version : 1.0
 * Create Date : 2021/2/20 15:14
 **/
@Slf4j
public class AccessLimitInterceptor extends HandlerInterceptorAdapter {

    private final RedisService redisService;

    public AccessLimitInterceptor(RedisService redisService) {
        this.redisService = redisService;
        log.info("[初始化-HandlerInterceptor] >>>>>>>>>>> AccessLimitInterceptor init.");
    }

    /**
     * @param request  请求
     * @param response 响应
     * @param handler  handler
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                return true;
            }

            // 有效时间
            int seconds = accessLimit.seconds();
            // 有效时间内最大次数
            int maxCount = accessLimit.maxCount();

            // redis中的key
            String key = request.getRequestURI();
            key = key + ":" + ServletUtil.getClientIP(request);

            // 获取用户请求次数
            Integer count = (Integer) redisService.get(key);

            if (count == null) {
                // 第一次请求
                redisService.set(key, 1, seconds);
            } else if (count < maxCount) {
                // +1
                redisService.incr(key, 1);
            } else {
                // 超出访问次数
                log.info("[AccessLimitInterceptor] 当前用户超出请求次数,请稍后再试!");
                throw new ApiException(ResultCode.FAIL.getCode(), "超出请求次数,请" + redisService.getExpire(key) + "秒后再试!");
            }
        }
        return true;
    }
}
